package controller;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;

import protocol.Cmd;

import protocol.CommSckServer;
import protocol.CommSckServerIn;
import protocol.CommSckServerOut;
import protocol.CommandRelay;
import protocol.Commands;
import simulatie.models.AGV;
import statter.Stats;

import xml.LeesXML;
import dbConn.DBConn;

/**
 * Dit is de Controller van het Containing programma, het stuurt de simulator
 * aan....
 * 
 * @author faceoff
 * @version 1.0
 */
public class Controller extends JFrame implements ActionListener {
	public static int SPEED = 500; //stel te snelheid in 1000 is normaal
	private Timer timer;
    private long time;
    private Calendar now = Calendar.getInstance();
    private Calendar cal = Calendar.getInstance();
    private Calendar dat = Calendar.getInstance();
    private TimerTask timertask,timertask2, timertask3;
    private Timestamp nextDelivery;
    private ResultSet cont;
	private static final long serialVersionUID = 1L;
	private JButton btnXML;
	private JButton btnStart;
	private JButton btnStop;
	private JButton btnToDB;
	private JButton btnOpenConn;
	private JButton btnStats;
	private JTextArea txtDatum;
	private JTextPane textPane;
	private JFileChooser xmlFile;
	private DBConn db1;
	private LeesXML leesXML;
	private JScrollPane sPanel;
	private JPanel cPanel;
	private Haven haven;
	private CommandRelay commRelay;
	private CommSckServerIn sckSrvIn;
	private CommSckServerOut sckSrvOut;
	private Commands commands;
	private Cmd command;
	private boolean okToSend = true;
	private boolean newSet = true;
	private boolean stuuragv = true;
	private Hashtable<Integer, Boolean> agvs = new Hashtable<Integer, Boolean>();
	private Hashtable<Integer, Boolean> kranen = new Hashtable<Integer, Boolean>();
	private boolean meer = true;
	private TimerTask timerSckChk;
	private Stats statter;
	

	
/**
 * Constructor
 */	
	public Controller(Stats statter) {
		super("Controller");
		this.statter = statter;
		for (int i=0; i <= 99; i++) {
			agvs.put(i, true);   //zet alle AGV's op Idle			
		}
		for (int j=1; j <= 51; j++) {
			kranen.put(j, true); //zet alle kranen op Idle			
		}
		timerSckChk = new TimerTask() {
			public void run() {
				command = commRelay.getInCmd();
				if (command != null) {
					System.out.println("contr: "+command.getCommand());				
					handleCommand(command);
				}
				
			}
		};
		
		timertask = new TimerTask() {
			public void run() {
				if (newSet && cal.getTimeInMillis() >= nextDelivery.getTime()) {
					System.out.println("newSet");
					nextDelivery = haven.getNextSetDate();
					cont = haven.getNextContainerSet();
					append(cal.getTime()+ ": Getting next Set");
					newSet=false;
				}
			    time = cal.getTimeInMillis();
	            cal.setTime( new Date( time + 500 ) );
	            txtDatum.setText(cal.getTime().toString());

	            getContainers();

			}			
		};   

		setupButtons();
		setupPanels();
		
		this.setLayout(new FlowLayout());
		this.add(cPanel);
		this.add(sPanel);
		
		this.pack();
		this.setSize(640, 480);
		this.setVisible(true);
		
		db1 = new DBConn();
		leesXML = new LeesXML(db1);
		
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);


	}
	
/**
 * Zet de eigenschappen en actionlisteners van de knoppen
 */
	private void setupButtons() {
		// Open XML FileDialog Button
		btnXML = new JButton("Open XML");
		btnXML.addActionListener(this);

		// Start Zet in Database
		btnToDB = new JButton("Naar DB");
		btnToDB.addActionListener(this);
		btnToDB.setEnabled(false);
		
		//Open de socket connectie
		btnOpenConn = new JButton("Open Connectie");
		btnOpenConn.addActionListener(this);

		// Start Simulatie
		btnStart = new JButton("Start");
		btnStart.addActionListener(this);
		btnStart.setEnabled(false);

		// Stop Simulatie
		btnStop = new JButton("Stop");
		btnStop.setEnabled(false);
		btnStop.addActionListener(this);
		
		btnStats = new JButton("Stats");
		btnStats.addActionListener(this);
		
		txtDatum = new JTextArea("");
	}
	
/**
 * Stel de panels in en plaats de knoppen
 */
	private void setupPanels() {
		// Text Pane
		textPane = new JTextPane();
		textPane.setAutoscrolls(true);
		textPane.setText("Dit is de Controller van het Containing Project van groep 4 \n" +
				"Open een XML, Zet deze in de DB.\n Klik dan op Open Connectie en laat de Simulator Connecten. \n" +
				"Druk dan op start en het programma gaat lopen");
		textPane.setFont(new Font("Verdana", Font.PLAIN, 14));
		textPane.setForeground(Color.WHITE);
		textPane.setBackground(Color.BLACK);
		textPane.setEditable(false);
		textPane.setVisible(true);
		
		// Scroll Pane
		sPanel = new JScrollPane(textPane);
		sPanel.setAutoscrolls(true);
		sPanel.setBorder(new TitledBorder(new EtchedBorder(), "Process",
				TitledBorder.DEFAULT_JUSTIFICATION,
				TitledBorder.DEFAULT_POSITION, null, new Color(0, 128, 255)));
		sPanel.setPreferredSize(new Dimension(620, 380));
		
		
		// Controls Pane
		cPanel = new JPanel(new FlowLayout());
		cPanel.setPreferredSize(new Dimension(600, 50));
		cPanel.setVisible(true);
		cPanel.add(btnXML);
		cPanel.add(btnToDB);
		cPanel.add(btnOpenConn);
		cPanel.add(btnStart);
		cPanel.add(btnStop);
		cPanel.add(btnStats);
		cPanel.add(txtDatum);
	}

/**
 * kijkt welke actie er moer worden uitgevoerd
 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == btnXML) {
			try {
				DialogFile();
			} catch (Exception e1) {
				
			}
		} else if (e.getSource() == btnToDB) {
			db1.open();
			leesXML.naarDB();
			db1.close();
			append("Containers in DataBase gezet");
		} else if (e.getSource() == btnStart) {
			btnStart.setEnabled(false);
			btnStop.setEnabled(true);
			 StartContr();		
		 } else if (e.getSource() == btnOpenConn) {
			 openConn();
			 append("Socket open!");
			 btnStart.setEnabled(true);
		} else if (e.getSource() == btnStop) {
			btnStart.setEnabled(true);
			btnStop.setEnabled(false);

			 StopContr();
		} else if (e.getSource() == btnStats) {
			statter.printGlobalStats();
		}
	}

/**
 * Maak een nieuwe haven, en open de connectie
 */	
	private void openConn() {
		haven = new Haven(statter);
		commRelay = new CommandRelay();
		sckSrvIn = new CommSckServerIn(commRelay, statter);
		sckSrvOut = new CommSckServerOut(commRelay, statter);
	}

/**
 * Opent een het scherm om een XML te laden
 * 
 * @throws Exception
 */
	private void DialogFile() throws Exception {
		// Open standard OpenFile dialog
		xmlFile = new JFileChooser("e:\\school\\Jaar 2\\Containing\\");
		xmlFile.setFileFilter(new Filter());

		// Fetch return value
		int iResVal = xmlFile.showOpenDialog(this);
		if (iResVal == JFileChooser.APPROVE_OPTION) {
			File xFile = xmlFile.getSelectedFile();
			if (xFile != null) {
				append("+ Parsing file: " + xFile + "");
				try {
					leesXML.OpenXML(xFile.getAbsolutePath());
					append(leesXML.aanvoer.size()
							+ " Containers geimporteerd");
					btnToDB.setEnabled(true);				
				} catch (IOException ioe) {
					System.out.println("I/O Exception Error");
					ioe.printStackTrace();
				} catch (ParserConfigurationException pce) {
					System.out.println("ParserConfiguration Exception Error");
					pce.printStackTrace();
				} catch (SAXException se) {
					System.out.println("SAX Exception Error");
				}
			}
		}
	}

/**
 * Voeg een regel toe aan de JPanel
 * 
 * @param msg
 */
	private void append(String msg) {
		textPane.setText(textPane.getText() + "\n" + msg);
	}

/**
 * Start de Controller
 */
	private void StartContr() {
		/* Als de controller gestart is kan de sim verbinding maken */
		cal.set(2004, 10, 29, 23, 50, 00);
		append("Controller wordt gestart!");
		timer = new Timer();
		timer.scheduleAtFixedRate(timerSckChk, 0, 10);
		this.cont = haven.getNextContainerSet();
		this.nextDelivery = haven.getNextSetDate();
		timer.scheduleAtFixedRate(timertask, SPEED, SPEED);
//		this.lastDelivery = new Timestamp(cal.getTimeInMillis());
	}

/**
 * Stopt de Conroller
 */
	private void StopContr() {
		timer.cancel();
		timer = null;
		cal.set(2004, 10, 29, 23, 50, 00);
		txtDatum.setText(cal.getTime().toString());
		textPane.setText("Controller is gestopt");
	}
    
	private void getContainers() {
			try {
				if (cont.next()) {
//					this.lastDelivery = new Timestamp(cal.getTimeInMillis());
					String vervoer = cont.getString(3);
					append(nextDelivery + " komt Container " + cont.getString(1) + " binnen per " + vervoer);
					if (vervoer.equals("vrachtauto")) {
						int agvnr = getFirstAGV();
						commRelay.addOutCmd(new Cmd(Commands.STUUR_AGV,agvnr,getFirstVkraan()));
						System.out.println("zend AGV " + agvnr);	
					} 
				} 
				else {
					newSet=true;
				}
			} catch (SQLException e) {
			e.printStackTrace();
			}
		} 
	

	@SuppressWarnings("deprecation")
	public void addToSchedule(Date date, final String action) {
    	dat.set(date.getYear(), date.getMonth(), date.getDay(), date.getHours(), date.getMinutes(), date.getSeconds()); //moment dat er iets gebeurd
		timertask2 = new TimerTask() {
			public void run() {
				append(action);
			}
		};
		long dif = now.getTimeInMillis() - cal.getTimeInMillis();
	    timer.schedule(timertask2, new Date(dat.getTimeInMillis() + dif));
    	
    }

	public void handleCommand(Cmd command2) {
		int cmd = command2.getCommand();
		System.out.println("Controller.handleCommand: " + cmd);
		switch (cmd) {
		case Commands.OK:
			okToSend = true;
			break;
		case Commands.OKV:
			int Okraan = getFirstOkraan();
//			kranen.put(command.getAgvNummer(), true); //zet de kraan weer op available
			commRelay.addOutCmd(new Cmd(Commands.NAAR_OPSLAG,command2.getAgvNummer(),getFirstOkraan()));
			System.out.println("AGV " + command2.getAgvNummer() + " is op bestemming V - Kraan " + command2.getKraannr() +
							" en gaat nu richting " + Okraan );
			break;
		case Commands.OKO:
			commRelay.addOutCmd(new Cmd(Commands.NAAR_IDLE,0,0));
			System.out.println("AGV is geleegd, ga Idle!");
			agvs.put(command2.getAgvNummer(), true); //Zet AGV op Idle
			break;
		}
	}
	
	private int getFirstTkraan() {
		int vKraan = 0;
		for (int i = 2; i <= 5; i++){
			if (kranen.get(i))
				vKraan = i;
		}
		kranen.put(vKraan, false);
		return vKraan;
	}

	private int getFirstZkraan() {
		int vKraan = 0;
		for (int i = 7; i <= 16; i++){
			if (kranen.get(i))
				vKraan = i;
		}
		kranen.put(vKraan, false);
		return vKraan;
	}

	private int getFirstBkraan() {
		int vKraan = 0;
		for (int i = 18; i <= 25; i++){
			if (kranen.get(i))
				vKraan = i;
		}
		kranen.put(vKraan, false);
		return vKraan;
	}

	private int getFirstVkraan() {
		int vKraan = 0;
		for (int i = 45; i >= 27; i--){
			if (kranen.get(i) == true)
				vKraan = i;
		}
		kranen.put(vKraan, false);
		return vKraan;
	}
	
	private int getFirstOkraan() {
		int vKraan = 0;
		for (int i = 47; i <= 51; i++){
			if (kranen.get(i))
				vKraan = i;
		}
		kranen.put(vKraan, false);
		return vKraan;
	}

	private int getFirstAGV() {
		int i = 0;
		int vAGV = -1;
		while (vAGV < 0) {
			if (agvs.get(i)) //als AGV is idle
				vAGV = i;
			i++;
		}
		agvs.put(vAGV, false);
		return vAGV;
	}
	
	
	
}

